﻿/*
 * @author: wizardc
 */

using System.Collections.Generic;
using Dou.Job;
using Dou.Utils;
using UnityEngine;

namespace Demo.WorldMap.Prefab
{
    /// <summary>
    /// 包含了当前渲染器下所有树的预制资源信息容器
    /// </summary>
    public class PrefabResContainer
    {
        static PrefabResContainer()
        {
            Recyclable.Register<PrefabResInfo>(100, () => new PrefabResInfo());
        }
        
        private Transform _parent;
        private PrefabStaticRenderRes[] _res;
        private PrefabStaticRenderTree _tree;
        
        private bool _enable = true;
        
        private List<int> _removeList;
        private List<int> _addList;

        private PrefabResCache _cache;
        private Dictionary<int, PrefabResInfo> _resInfoMap;
        
        /// <summary>
        /// 初始化容器
        /// </summary>
        public void Init(Transform parent, PrefabStaticRenderRes[] res, PrefabStaticRenderTree tree)
        {
            _parent = parent;
            _res = res;
            _tree = tree;
            
            _removeList = new List<int>();
            _addList = new List<int>();
            
            _cache = new PrefabResCache(_res);
            _cache.onLoadComplete += OnLoadComplete;
            _resInfoMap = new Dictionary<int, PrefabResInfo>();
        }

        /// <summary>
        /// 设置是否显示
        /// </summary>
        public void SetEnable(bool enable)
        {
            if (_enable == enable)
            {
                return;
            }
            _enable = enable;
            foreach (var kv in _resInfoMap)
            {
                var info = kv.Value;
                info.go.SetActive(_enable);
            }
        }

        /// <summary>
        /// 添加一个显示对象
        /// </summary>
        [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
        [Il2CppSetOption(Option.NullChecks, false)]
        public void AddObj(int nodeIndex)
        {
            _addList.Add(nodeIndex);
        }

        /// <summary>
        /// 移除一个显示对象
        /// </summary>
        [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
        [Il2CppSetOption(Option.NullChecks, false)]
        public void RemoveObj(int nodeIndex)
        {
            _removeList.Add(nodeIndex);
        }

        private void OnLoadComplete(int resId, GameObject asset)
        {
            foreach (var kv in _resInfoMap)
            {
                var info = kv.Value;
                if (info.resId == resId && info.state == PrefabResState.Loading)
                {
                    var go = GameObject.Instantiate(asset);
                    go.transform.SetParent(_parent, false);
                    info.state = PrefabResState.Complete;
                    info.go = go;
                    SetPosition(info);
                }
            }
        }

        /// <summary>
        /// 更新显示
        /// </summary>
        public void Update()
        {
            // 先移除
            if (_removeList.Count > 0)
            {
                for (int i = 0; i < _removeList.Count; i++)
                {
                    var nodeIndex = _removeList[i];
                    var info = _resInfoMap[nodeIndex];
                    if (info.go != null)
                    {
                        _cache.RecycleRes(info.resId, info.go);
                    }
                    Recyclable.Recycle(info);
                    _resInfoMap.Remove(nodeIndex);
                }
                _removeList.Clear();
            }
            // 再增加
            if (_addList.Count > 0)
            {
                for (int i = 0; i < _addList.Count; i++)
                {
                    var nodeIndex = _addList[i];
                    var node = _tree.nodes[nodeIndex];
                    
                    var info = Recyclable.Get<PrefabResInfo>();
                    info.nodeIndex = nodeIndex;
                    info.resId = node.resId;
                    info.bounds = node.bounds;
                    info.matrix = _tree.matrixes[node.matrixId];

                    // 获取或加载对应预制
                    if (_cache.GetRes(info.resId, out var go))
                    {
                        go.transform.SetParent(_parent, false);
                        info.state = PrefabResState.Complete;
                        info.go = go;
                        SetPosition(info);
                    }
                    else
                    {
                        info.state = PrefabResState.Loading;
                    }
                    
                    _resInfoMap.Add(nodeIndex, info);
                }
                _addList.Clear();
            }
        }

        private void SetPosition(PrefabResInfo info)
        {
            var trans = info.go.transform;
            trans.position = info.matrix.GetColumn(3);
            trans.rotation = info.matrix.rotation;
            trans.localScale = info.matrix.lossyScale;
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            foreach (var kv in _resInfoMap)
            {
                var info = kv.Value;
                if (info.go != null)
                {
                    GameObject.Destroy(info.go);
                }
            }
            _resInfoMap.Clear();
            _cache.Dispose();
        }
        
#if UNITY_EDITOR

        public void DrawObjAABB()
        {
            Gizmos.color = Color.green;
            foreach (var kv in _resInfoMap)
            {
                var info = kv.Value;
                Gizmos.DrawWireCube(info.bounds.center, info.bounds.size);
            }
        }
        
#endif

    }
}
